<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	
	<script>


		/*工厂模式*/
		function Dog(name,color) {
			var obj = {
				name: name,
				color: color
			};
			return obj;
		};

		var dog1 = Dog('dog3', 'yellow');
		var dog2 = Dog('dog4', 'block');



		/*构造函数*/
		function Dog(name,color) {
			this.name = name;	/*现在this指向window*/
			this.color = color;
		}

		var dog5 = new Dog('dog','gray');	/*用new来调用函数this现指向上面的实例*/



		/*原型prototype模式*/
		function Dog(name,color) {
			this.name = name;	/*现在this指向window*/
			this.color = color;
		}

		Dog.prototype = {
			type: 'haha',
			run: function(){
				console.log('sitiaotui')
			}
		}

		var dog6 = new Dog('dog3', 'yellow');
		var dog7 = new Dog('dog4', 'block');



		/*继承-1*/
		function Animal() {
			this.type = 'animal';
			this.color = undefined;
			this.eat = function() {
				console.log('eating...')
			}
		}

		function Dog(name) {
			this.name = name;
			this.kanmen = function() {
				console.log(this.name + "正在看门...")
			}
		}

		function Cat(name) {
			this.name = name;
			this.zhals = function() {
				console.log(this.name + "正在抓老鼠...")
			}
		}

		Dog.prototype = new Animal();
		//把Dog的prototype对象指向一个Animal的实例，
		//相当于删除prototype原来的值，附一个新的值。
		Dog.prototype.constructor = Dog;

		var d1 = new Dog('wangcai');
		var c1 = new Cat('mimi');



		/*继承-2*/
		/*直接继承prototype，把不变的属性直接写到父类的prototype，
		让子类跳过父类，直接继承父类的prototype。*/
		function Animal(){
			this.color = undefined;
		};

		Animal.prototype = {
			type ； 'animal'，
			eat ； function() {
				console.log('eating...')
			}
		}

		function Dog(name) {
			this.name = name;
			this.kanmen = function() {
				console.log(this.name + "正在看门...")
			}
		}

		function Cat(name) {
			this.name = name;
			this.zhals = function() {
				console.log(this.name + "正在抓老鼠...")
			}
		}

		Dog.prototype = Animal.prototype;
		Dog.prototype.constructor = Dog;
		/*相比于方法一效率高，不用新建Animal实例，节约内存，
		但是子类和父类的prototype都指向了同一个对象，会导致
		子类的prototype修改会改变父类的prototype。*/



		/*继承-3	借助空对象*/
		var F = function() {};
		F.prototype = Animal.prototype;
		Dog.prototype = new F();
		Dog.prototype.constructor = Dog;
		/*F是空对象，几乎不占内存，而且修改子类的prototype，不会影响父类的prototype。*/

		/*封装成一个函数*/
		function jicheng(zilei,fulei) {
			var F = function() {};
			F.prototype = fulei.prototype;
			zilei.prototype = new F();
			zilei.prototype.constructor = zilei;
			zilei.super = fulei.prototype;	//提供一个得到父对象的通道，可以不写
		}

		//用法
		jicheng(Dog,Animal);
		var dog1 = new Dog('wangcai' , 'yellow');
		console.log(dog1.type); // animal



		/*继承-4	拷贝继承*/
		function Animal() {};

		Animal.prototype.type ="animal";

		function jicheng2(zi,fu) {
			var z = zi.prototype;
			var f = fu.prototype;

			for (var i in z) {
				z[i] = f[i]
			}
			z.super = f;
		}	/*不用再新建对象，也不用重新指向*/

		//用法
		jicheng2(Dog,Animal);
		var dog1 = new Dog('wangcai' , 'yellow');
		console.log(dog1.type); // animal



		/*非构造函数继承*/
		var Animal = {
			type: 'animal'
		};

		var Dog = {
			color: 'yellow'
		}

		function object(o) {
			function F() {};
			F.prototype = o;
			return new F();
		}

		//用法
		var Dog = object(Animal);	//在父对象的基础上生成子对象
		Dog.color = 'yellow';	//加上子对象的本身
		console.log(Dog.type);	//animal



		/*继承  浅复制*/
		function qCopy(fu) {
			var zi = {};
			for (var i in fu) {
				zi[i] = fu[i]
			}
			return zi;
		}

		var Dog = qCopy(Animal);
		Dog.name = 'dog8';
		Dog.kanm = function() {
			console.log(this.name + '正在看门。。。')
		}
		/*如果父对象的属性是一个数组或者对象，子对象只是复制了一个
		内存指针，而不是真正的复制，因此存在父对象被修改的可能*/



		/*继承  深复制*/
		function deepCopy(p,c) {
			var c = c || {};
			for(var i in p) {
				if(typeof p[i] === 'object') {
					c[i] = (p[i].constructor === Array) ? [] : {};
					deepCopy(p[i],c[i])				}
			} else {
				c[i] = p[i];
			}
			return c;
		}

		// 用法
		var Dog = deepCopy(Animal);





		/*call和apply*/
		function plus(x,y) {
			return x + y;
		}

		function minus(x,y) {
			return x - y;
		}

		var n1 = plus.call(null,3,5);	//8
		var n2 = minus.call(null,8,5);	//2	

		var n1 = plus.apply(null,[3,4]);	//7	
		var n2 = minus.apply(null,[8,5]);	//3	
		/*它们的第一个参数都是需要调用的函数对象,call()传的值是以
		逗号分隔的任意参数，而apply()传的剩余值必须为数组*/

	</script>
</body>
</html>